﻿using System;
using System.Linq;
using System.Linq.Expressions;
using OS.Infrastructure.Domain;

namespace TaskKernel.Domain.Nhibernate.NHibernateLayer
{
    internal class  EmptySpecification : Specification<Task>
    {
        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => true;
        }
    }
    internal class ContainsInTaskName : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInTaskName(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.TaskName.Contains(_nameToMatch);
        }
    }
    internal class ContainsInTaskId : Specification<Task>
    {
        private readonly Guid _nameToMatch;

        public ContainsInTaskId(Guid nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.UID == _nameToMatch;
        }
    }

    internal class ContainsInTaskCode : Specification<Task>
    {
        private readonly int _nameToMatch;

        public ContainsInTaskCode(int nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Code == _nameToMatch;
        }
    }
  
    internal class ContainsInFileName : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInFileName(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Files.Any(p => p.FileName.Contains(_nameToMatch));
        }
    }

    internal class WhereTaskStatusIs : Specification<Task>
    {
        private readonly TaskStatus _nameToMatch;

        public WhereTaskStatusIs(TaskStatus nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Status == _nameToMatch;
        }
    }

    public class TaskIsNew : Specification<Task>
    {
        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Status == TaskStatus.InProgress && x.Executor == null;
        }
    }

    public class TaskIsInProgress : Specification<Task>
    {
        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Status == TaskStatus.InProgress && x.Executor != null;
        }
    }

    public class TaskWaitingToClose : Specification<Task>
    {
        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Status == TaskStatus.WaitingToClose;
        }
    }

    public class HasExecutor : Specification<Task>
    {
        private readonly Account _account;

        public HasExecutor(Account account)
        {
            _account = account;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Executor.UID == _account.UID;
        }
    }

    internal class ContainsInExecutorFullName : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInExecutorFullName(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Executor.FullName.Contains(_nameToMatch);
        }
    }

    internal class ContainsInTag : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInTag(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Tag.Contains(_nameToMatch);
        }
    }

    internal class ContainsInDepartmentName : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInDepartmentName(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Department.DepartmentName.Contains(_nameToMatch);
        }
    }

    internal class ContainsInOwnerFullName : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInOwnerFullName(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Owner.FullName.Contains(_nameToMatch);
        }
    }

    internal class ContainsInParticipantFullName : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInParticipantFullName(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.ParticipantsWithOwner.Any(p => p.Login.FullName.Contains(_nameToMatch));
        }
    }

    internal class ContainsInComment : Specification<Task>
    {
        private readonly string _nameToMatch;

        public ContainsInComment(string nameToMatch)
        {
            _nameToMatch = nameToMatch;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.HistoryEntries.Any(p => p.Comment.Contains(_nameToMatch));
        }
    }

    internal class AccountIsOwner : Specification<Task>
    {
        private readonly Account _account;

        public AccountIsOwner(Account account)
        {
            _account = account;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Owner == _account;
        }
    }

    internal class InDepartment : Specification<Task>
    {
        private readonly Department _department;

        public InDepartment(Department department)
        {
            _department = department;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Department == _department;
        }
    }

    internal class AccountIsExecutor : Specification<Task>
    {
        private readonly Account _account;

        public AccountIsExecutor(Account account)
        {
            _account = account;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Executor == _account;
        }
    }

    internal class AccountIsParticipant : Specification<Task>
    {
        private readonly Account _account;

        public AccountIsParticipant(Account account)
        {
            _account = account;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.ParticipantsWithOwner.Any(p => p.Login.UID == _account.UID);
        }
    }

    internal class AccountExecutorInDepartment : Specification<Task>
    {
        private readonly Account _account;

        public AccountExecutorInDepartment(Account account)
        {
            _account = account;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return
                x =>
                x.Department.UsersWithRole.Any(
                    p => p.User.UID == _account.UID && (p.Role == RoleEnum.Admin || p.Role == RoleEnum.Executor));
        }
    }

    internal class DateCreatePeriod : Specification<Task>
    {
        private readonly DateTime _dateFrom;
        private readonly DateTime _dateTo;

        public DateCreatePeriod(DateTime dateFrom, DateTime dateTo)
        {
            _dateFrom = dateFrom;
            _dateTo = dateTo;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.DateCreate >= _dateFrom && x.DateCreate <= _dateTo;
        }
    }

    internal class DateClosePeriod : Specification<Task>
    {
        private readonly DateTime _dateFrom;
        private readonly DateTime _dateTo;

        public DateClosePeriod(DateTime dateFrom, DateTime dateTo)
        {
            _dateFrom = dateFrom;
            _dateTo = dateTo;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.DateClose >= _dateFrom && x.DateClose <= _dateTo;
        }
    }

    internal class WhereExpirationReminder : Specification<Task>
    {
        private readonly DateTime _dateTime;

        public WhereExpirationReminder(DateTime now)
        {
            _dateTime = now;
        }

        public override Expression<Func<Task, bool>> IsSatisfiedBy()
        {
            return x => x.Reminders.Any(p => p.DateTime == _dateTime.Round(DateTimeExtensions.RoundTo.Minute));
        }
    }

    internal class WhereTasksDateCreate
    {
        private readonly DateTime _highRounded;
        private readonly DateTime _lowRounded;

        public WhereTasksDateCreate(DateTime now)
        {
            _lowRounded = now.Round(DateTimeExtensions.RoundTo.Minute);
            _highRounded = now.Round(DateTimeExtensions.RoundTo.Minute).AddMinutes(1);
        }

        public virtual Func<Task, bool> IsSatisfiedBy()
        {
            return
                x =>
                x.DateCreate > _lowRounded.ReplaceDate(x.DateCreate) &&
                x.DateCreate < _highRounded.ReplaceDate(x.DateCreate);
        }
    }
}